package com.marketlive.app.b2c.account;

/*
(C) Copyright MarketLive. 2006. All rights reserved.
MarketLive is a trademark of MarketLive, Inc.
Warning: This computer program is protected by copyright law and international treaties.
Unauthorized reproduction or distribution of this program, or any portion of it, may result
in severe civil and criminal penalties, and will be prosecuted to the maximum extent
possible under the law.
*/

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.*;
import org.apache.struts.validator.Resources;
import org.marketlive.biz.account.IAccountManager;
import org.marketlive.biz.session.context.ICommerceSession;
import org.marketlive.entity.account.ICustomer;
import org.marketlive.entity.account.IHint;
import org.marketlive.system.config.IConfigurationManager;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.marketlive.app.b2c.WebUtil;
import com.marketlive.app.b2c.common.constants.*;

/**
 * Action to process customer information: email, password and password recovery hint.
 * The shopper is taken to the RegisterAddressAction upon success and a customer record is created.
 * The customer is also logged in and registered in the commerce session.
 * For details about parameters of methods please see the package description.
 */
public class RegisterUserAction extends AbstractAccountAction {
    private static Log log = LogFactory.getLog(RegisterUserAction.class);

    private static final String CHECKOUT_FORWARD_PREFIX = "CHECKOUT";

    /** Reference to the Account Manager for the EmailPassword.jsp tile. */
    private IAccountManager accountManager;

    /** Configuration Manager. */
    IConfigurationManager configManager;


    /**
     * Return a reference to the Account Manager.
     * @return
     */
    public IAccountManager getAccountManager() {
        return accountManager;
    }

    /**
     * Set the AccountManager reference (done by Spring see action-servlet.xml).
     * @param accountManager
     */
    public void setAccountManager(IAccountManager accountManager) {
        this.accountManager = accountManager;
    }

	/**
	 * Setter for configManager property.
	 *
	 * @param configManager
	 */
	public void setConfigManager(IConfigurationManager configManager) {
		this.configManager = configManager;
	}

	
    /**
     * Executes default method (view) if method parameter is not specified.
     *
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    protected ActionForward unspecified(ActionMapping mapping,
                                        ActionForm form,
                                        HttpServletRequest request,
                                        HttpServletResponse response) throws Exception {
        return view(mapping, form, request, response);
    }

    /**
     * Prepare the page to be displayed.
     * For details about parameters of method please see the package description.
     */
    public ActionForward view(ActionMapping mapping,
                              ActionForm form,
                              HttpServletRequest request,
                              HttpServletResponse response)
            throws Exception {


        AccountRegisterForm accountRegisterForm = AccountDispatcherAction.getAccountRegisterForm(request);

        // set up header nav
        accountRegisterForm = (AccountRegisterForm)form;
        accountRegisterForm.setNavigationImage(ConfigProperties.REGISTER_USER_NAV_IMAGE);
        accountRegisterForm.setNavigationMsg(Messages.REGISTER_NAV_MESSAGE);
        accountRegisterForm.setRequiredMsgShown(true);
        accountRegisterForm.setShowNavigation(false);
        accountRegisterForm.setCurrentPage("registeruser");
        accountRegisterForm.setLoginEmail("");
        accountRegisterForm.setLoginPassword("");
        accountRegisterForm.setLoginPasswordConfirm("");

        request.setAttribute(RequestParams.HREF_REQUEST_PARAM_NAME, "account");

        try {
            log.debug("in view method");
            boolean hintConfigured = configManager.getAsBoolean(ConfigProperties.REGISTER_USER_HAS_HINT);
            if (hintConfigured) {
                accountRegisterForm.setHintShown(true);
            } else {
                accountRegisterForm.setHintShown(false);
            }

        } catch (Exception e) {
            log.debug("Exception is: " + e.getMessage());
        }
        return super.view(mapping, form, request, response);
    }

    /**
     * Process the form and save the customer contact upon success.
     * For details about parameters of method please see the package description.
     */
    public ActionForward submit(ActionMapping mapping,
                                ActionForm form,
                                HttpServletRequest request,
                                HttpServletResponse response )
        throws Exception
    {

        log.debug("AccountRegisterUser in execute method");
        AccountRegisterForm registerUserForm = (AccountRegisterForm) form;
        ICommerceSession commerceSession = WebUtil.getCommerceSession(request);
        ICustomer customer = commerceSession.getCustomer();
        String whence = null;

        String userName = commerceSession.getCustomer().getEmail();
        String userPassword = registerUserForm.getLoginPassword();
        String passwordConfirm = registerUserForm.getLoginPasswordConfirm();
        boolean hintConfigured = configManager.getAsBoolean(ConfigProperties.REGISTER_USER_HAS_HINT);
        IHint hint = commerceSession.getCustomer().getHint();
        String hintAnswer = commerceSession.getCustomer().getHintAnswer();

        //log.debug("form email:" + userName + "form  password:" + userPassword + "form hintId:" +
        //        hint.getPk().getAsString() +
        //        "form hintAnswer" + hintAnswer);

        if (passwordConfirm != null) {
            //Avoid logging PAN
            //log.debug("passwordConfirm=" + passwordConfirm);

            if (!passwordConfirm.equals(userPassword)) {
                // redisplay page with error message
                postGlobalError(Errors.REGISTER_USER_PASSWORDS_NOMATCH,request);
                return WebUtil.findForward(request, mapping, ActionForwards.FAILURE_KEY);
            }
        } else {
            // redisplay page with error message
            postGlobalError(Errors.REGISTER_USER_PASSWORDS_NOMATCH,request);
            return WebUtil.findForward(request, mapping, ActionForwards.FAILURE_KEY);
        }

        try {

            boolean addedPasswordRecoveryInfo = false;
            boolean foundCustomer = accountManager.isCustomerTaken(userName);
            if (foundCustomer == true) {
                // redisplay page with error message
                postGlobalError(Errors.REGISTER_USER_USERNAME_EXISTS,request);
                return WebUtil.findForward(request, mapping, ActionForwards.FAILURE_KEY);
            }

            // register the customer
            String encryptedPassword = accountManager.encryptCustomerPassword(userPassword);
            customer = commerceSession.register(userName, encryptedPassword);
            if (customer != null) {

                //Avoid logging PAN
                //log.debug("customer email" + customer.getEmail() + " customer password" + customer.getPassword());
                if (hintConfigured) {
                    //Avoid logging PAN
                    //log.debug("hintId: " + hint.getPk().getAsString() + " - hintAnswer: " + hintAnswer);
                    addedPasswordRecoveryInfo = accountManager.updatePasswordRecoveryInfo(customer,
                           hint, hintAnswer);
                    //Avoid logging PAN
                    //log.debug("addedPasswordRecoveryInfo=" + addedPasswordRecoveryInfo);
                    if (!addedPasswordRecoveryInfo) {
                        // redisplay page with error message
                        // todo need error message or handle this as a generic error
                        // todo perhaps AccountManager should throw runtime exception if update fails...
                        postGlobalError("Please try again", request);
                        return WebUtil.findForward(request, mapping, ActionForwards.FAILURE_KEY);
                    }
                }
                String email = customer.getEmail();
            }
        } catch (Exception e) {
            log.error("Exception is: " + e);
        }

        // clear the password confirm field
        registerUserForm.setLoginPasswordConfirm(null);
        whence = registerUserForm.getWhence();
        // Determine whether the register page was invoked from checkout
        if (null != whence && whence.contains(CHECKOUT_FORWARD_PREFIX)) {
            // clear form flag
            registerUserForm.setWhence(null);
            return WebUtil.findForward(request, mapping, whence);
        } else {
            return WebUtil.findForward(request, mapping, ActionForwards.SUCCESS_KEY);
        }
	}

    /**
     * Perform validation on submit only.
     * For details about parameters of method please see the package description.
     */
    public ActionMessages validate(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request) {
        log.debug("validate() start");
        try {
            String method = super.getMethodName(mapping, form, request, null, RequestParams.METHOD);
            if (RequestParams.METHOD_SUBMIT.equals(method) ) {
                boolean hintConfigured = configManager.getAsBoolean(ConfigProperties.REGISTER_USER_HAS_HINT);
                ActionMessages errors = super.validate(mapping,form,request,mapping.getPath());
                if (errors.isEmpty()) {
                    errors = new ActionErrors();
                }
                if (hintConfigured) {
                    AccountRegisterForm registerUserForm = (AccountRegisterForm) form;
                    IHint hint = registerUserForm.getCustomer().getHint();
                    String hintAnswer = registerUserForm.getCustomer().getHintAnswer();
                    boolean success = true;

                    if (null == hint) {
                        errors.add(ActionMessages.GLOBAL_MESSAGE,
                            new ActionMessage(Errors.REQUIRED,
                                    Resources.getMessage(request, Errors.REGISTER_USER_RECOVERY_QUESTION), request));
                    } else {
                        //success = HintQuestionValidator.isValid(hint.getPk().getAsString(), request);
                        if (!success) {
                            errors.add(ActionMessages.GLOBAL_MESSAGE,
                                new ActionMessage(Errors.REGISTER_USER_INVALID_HINT, request));
                        }
                    }

                    if ((null == hintAnswer) || (hintAnswer.trim().length() < 1)) {
                        errors.add(ActionMessages.GLOBAL_MESSAGE,
                                new ActionMessage(Errors.REQUIRED,
                                        Resources.getMessage(request, Errors.REGISTER_USER_RECOVERY_ANSWER), request));
                    } else {
                        int hintMaxLength = configManager.getAsInt(ConfigProperties.REGISTER_USER_HINT_MAXLENGTH);
                        if(hintAnswer.length() > hintMaxLength) {
                            String recoveryAnswer = Resources.getMessage(request, Errors.REGISTER_USER_RECOVERY_ANSWER);
                            String [] substitutionValues = {recoveryAnswer, String.valueOf(hintMaxLength)};
                            errors.add(ActionMessages.GLOBAL_MESSAGE,
                                    new ActionMessage(Errors.FIELD_MAX_LENGTH_INVALID,substitutionValues, request));
                        }
                    }
                }
                if (!errors.isEmpty()) {
                    saveErrors(request, errors);
                    return errors;
                }
            } else {
                return null;
            }
        } catch (Exception e) {
            log.debug("Exception: " + e);
        }
        return null;
    }
}
